﻿using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using OwnZTec.OwnZCraft.Common;
using OwnZTec.OwnZCraft.ServerAdmin.Properties;
using Timer = System.Threading.Timer;

namespace OwnZTec.OwnZCraft.ServerAdmin
{
    public partial class frmServerAdm : Form
    {
        #region -- Members and Constructors -----------------------------------------------------------------------------------------------
        delegate void StringParameterDelegate(string value);
        delegate bool BooleanParameterDelegate(bool value);

        private bool EnableServerMonitor { get; set; }
        private bool RestarServerWhenDown { get; set; }
        private bool EnableFileLog { get; set; }
        private bool ServerRunning { get; set; }

        public frmServerAdm()
        {
            InitializeComponent();
        }
        #endregion ------------------------------------------------------------------------------------------------------------------------

        #region -- Events -----------------------------------------------------------------------------------------------------------------
        private void Form1_Load(object sender, EventArgs e)
        {
            Log("Initializing application...");

            gpbServerMonitor.Enabled = chkRestart.Checked = chkEnableServerMonitor.Checked = chkEnableLog.Checked = false;

            Log("Server monitor is disabled.");

            Log("Initialization Completed.");

            UpdateServerStatus();
        }

        private void chkRestart_CheckedChanged(object sender, EventArgs e)
        {
            RestarServerWhenDown = chkRestart.Checked;

            Log(RestarServerWhenDown ? "Restart server enabled." : "Restart server disabled.");
        }

        private void chkEnableServerMonitor_CheckedChanged(object sender, EventArgs e)
        {
            tmrCheckTimer.Enabled = gpbServerMonitor.Enabled = EnableServerMonitor = chkEnableServerMonitor.Checked;

            tmrCheckTimer.Interval = Convert.ToInt32(txtCheckInterval.Text) * 1000;

            if (EnableServerMonitor)
                Log("Server monitor enabled. Interval: " + tmrCheckTimer.Interval / 1000);
            else
                Log("Server monitor disabled.");
        }

        private void chkEnableLog_CheckedChanged(object sender, EventArgs e)
        {
            EnableFileLog = chkEnableLog.Checked;

            Log(EnableFileLog ? "File logging enabled." : "File logging disabled.");
        }

        private void tmrCheckTimer_Tick(object sender, EventArgs e)
        {
            Log("Running scheduled monitor...");

            tmrCheckTimer.Enabled = false;

            tmrCheckTimer.Interval = Convert.ToInt32(txtCheckInterval.Text) * 1000;

            var thd = new Thread(new ThreadStart(RunCheck));
            thd.Start();
        }

        private void osSrvStatus_Click(object sender, EventArgs e)
        {
            UpdateServerStatus();
        }

        private void txtCheckInterval_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != (char)13) return;

            var interval = String.IsNullOrEmpty(txtCheckInterval.Text) ? 0 : Convert.ToInt32(txtCheckInterval.Text);

            if (interval > 0)
            {
                tmrCheckTimer.Interval = interval * 1000;
                tmrCheckTimer.Enabled = true;

                Log("Interval updated to: " + interval + " seconds.");
            }
            else
            {
                tmrCheckTimer.Enabled = false;

                Log("Invalid time set for interval. Timer disabled.");
            }
        }

        private void frmServerAdm_SizeChanged(object sender, EventArgs e)
        {
            ShowInTaskbar = WindowState != FormWindowState.Minimized;
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            WindowState = FormWindowState.Normal;
        }
        #endregion ------------------------------------------------------------------------------------------------------------------------

        #region -- Methods ----------------------------------------------------------------------------------------------------------------
        private void RunCheck()
        {
            var enableTimerDelegate = new MethodInvoker(EnableTimer);

            if (!EnableServerMonitor)
            {
                Log("Server monitor is disabled.");
                Invoke(enableTimerDelegate);
                return;
            }

            var mcSrvStatus = UpdateServerStatus();

            if (mcSrvStatus)
            {
                Invoke(enableTimerDelegate);
                return;
            }

            if (!RestarServerWhenDown)
            {
                Log("Server restarting is disabled. No action taken.");
                Invoke(enableTimerDelegate);
                return;
            }

            Log("Checking if Java is running...");

            if (ServerAdmin.IsJavaRunning())
            {
                Log("Java is running. Attempting to stop Java process...");

                var res = ServerAdmin.StopServer();

                var forceShutdown = false;

                if (res)
                {
                    Log("Stop command sent. Waiting 10 seconds for server to close...");
                    Wait(10000);

                    Log("Checking if java has closed...");

                    if (ServerAdmin.IsJavaRunning())
                    {
                        Log("Java did not stop...");
                        forceShutdown = true;
                    }
                }
                else
                {
                    Log("It wasn't possible to send Stop command.");
                    forceShutdown = true;
                }

                if (forceShutdown)
                {
                    Log("Forcing Java shutdown...");

                    ServerAdmin.ShutdownServer();

                    Log("Shutdown command sent. Waiting 5 seconds for server to close...");
                    Wait(5000);

                    Log("Checking if java has closed...");

                    if (ServerAdmin.IsJavaRunning())
                    {
                        Log("It was not possible to automatically stop the Java process, please connect to the server to check the cause.");
                        Invoke(enableTimerDelegate);
                        return;
                    }
                }

                Log("Java stopped successfully.");
            }

            Log("Java stopped. Attempting to restart...");

            if (ServerAdmin.StartServer())
            {
                Log("Start command sent. Waiting 15 seconds for server to start...");
                Wait(15000);

                Log("Checking if java has started...");

                if (ServerAdmin.IsJavaRunning())
                {
                    Log("Server has started successfully");
                    Invoke(enableTimerDelegate);

                    UpdateServerStatus(false);
                    return;
                }
            }

            Log("It was not possible to automatically start the Java process, please connect to the server to check the cause.");
            tmrCheckTimer.Enabled = true;
            return;
        }

        private bool UpdateServerStatus(bool log = true)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                return (bool)Invoke(new BooleanParameterDelegate(UpdateServerStatus), new object[] { log });
            }

            if (log)
                Log("Checking Server Status...");

            ServerRunning = ServerAdmin.CheckServerStatus();

            osSrvStatus.FillColor = ServerRunning ? Color.Green : Color.Red;

            if (log)
                Log(ServerRunning ? "Server is Running. :D" : "Server is not responding. ;(");

            notifyIcon1.Icon = ServerRunning ? Resources.logoOn : Resources.logoOff;

            return ServerRunning;
        }

        private void Log(string message)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new StringParameterDelegate(Log), new object[] { message });
                return;
            }

            message = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss.fff => ") + message;

            if (txtLog.Text.Length == 0)
                txtLog.AppendText(message);
            else
                txtLog.AppendText("\r\n" + message);

            txtLog.ScrollToCaret();
        }

        private void Wait(int milliseconds)
        {
            const int innerSleep = 100;

            for (var i = 0; i <= milliseconds / innerSleep; i++)
            { Thread.Sleep(innerSleep); }
        }

        public void EnableTimer()
        {
            tmrCheckTimer.Enabled = true;
        }
        #endregion ------------------------------------------------------------------------------------------------------------------------
    }

    public static class ServerAdmin
    {
        public static bool CheckServerStatus()
        {
            return Server.ServerStatus();
        }

        public static bool IsJavaRunning()
        {
            return Server.IsJavaRunning();
        }

        public static bool ShutdownServer()
        {
            return Server.ShutdownServer();
        }

        public static bool StopServer()
        {
            return Server.StopServer();
        }

        public static bool StartServer()
        {
            return Server.StartServer();
        }
    }
}
